package com.xingu.xg.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xingu.xg.common.enums.OperationTypeEnum;
import com.xingu.xg.converter.TreeNodeConverter;
import com.xingu.xg.domain.dto.TreeNodeDto;
import com.xingu.xg.domain.entity.TreeNode;
import com.xingu.xg.domain.request.AddNodeQuery;
import com.xingu.xg.domain.request.CopyNodeQuery;
import com.xingu.xg.domain.request.DeleteNodeQuery;
import com.xingu.xg.mapper.TreeNodeMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class TreeNodeServiceImpl extends ServiceImpl<TreeNodeMapper, TreeNode> implements TreeNodeService {


    private final TreeNodeMapper treeNodeMapper;

    /**
     * 查询树形结构列表
     */
    public List<TreeNodeDto> queryTreeList() {
        List<TreeNode> rootNodes = treeNodeMapper.selectList(Wrappers.lambdaQuery(TreeNode.class)
                // .eq(TreeNode::getTreeId, treeId)
                .orderByAsc(TreeNode::getDepth)
                .orderByAsc(TreeNode::getTreeOrder)
        );
        return buildTree(rootNodes).stream().filter(node -> node.getParentId() == 0).toList();
    }

    private List<TreeNodeDto> buildTree(List<TreeNode> nodes) {
        // 转成 map， 方便取值
        List<TreeNodeDto> tree = TreeNodeConverter.INSTANCE.toDto(nodes);
        Map<Long, TreeNodeDto> treeMap = tree.stream()
                .collect(Collectors.toMap(TreeNodeDto::getId, node -> node));
        tree.forEach(node -> {
            if (0 == node.getParentId()) {
                // 规定，0为根节点
                return;
            }
            TreeNodeDto parent = treeMap.get(node.getParentId());
            if (parent == null) {
                return;
            }
            parent.getChildren().add(node);
            parent.setIsLeaf(Boolean.FALSE);
        });
        return tree;
    }

    /**
     * 向上向下增加节点（子节点） TODO depth 计算
     */
    @Transactional(rollbackFor = Exception.class)
    public List<TreeNodeDto> addNode(AddNodeQuery request) {
        TreeNode currentNode = treeNodeMapper.selectById(request.getSelectedId());
        TreeNode newNode = new TreeNode();
        newNode.setName(request.getNodeName());
        newNode.setTreeId(currentNode.getTreeId());
        switch (request.getOpType()) {
            case OperationTypeEnum.CHILD -> {
                // 创建新子节点，旧子节点顺序后移
                newNode.setParentId(currentNode.getId());
                newNode.setTreeOrder((short) 1);
                // 获取当前节点的子节点，并设置新节点的顺序
                this.update(Wrappers.lambdaUpdate(TreeNode.class)
                        .setSql("tree_order = tree_order + 1")
                        .eq(TreeNode::getTreeId, currentNode.getTreeId())
                        .eq(TreeNode::getParentId, currentNode.getId())
                );
                treeNodeMapper.insert(newNode);
            }
            case OperationTypeEnum.PARENT -> {
                // 创建父节点
                newNode.setParentId(currentNode.getParentId());
                newNode.setTreeOrder(currentNode.getTreeOrder());
                treeNodeMapper.insert(newNode);
                // 移动当前节点
                currentNode.setParentId(newNode.getId());
                currentNode.setTreeOrder((short) 1);
                treeNodeMapper.updateById(currentNode);
            }
            case OperationTypeEnum.SIBLING_UP -> {
                // 向上创建同级节点，当前节点及后面的同级节点顺序后移
                newNode.setParentId(currentNode.getParentId());
                newNode.setTreeOrder(currentNode.getTreeOrder());
                // currentNode.setOrder((short)(currentNode.getOrder() + 1));
                this.update(Wrappers.lambdaUpdate(TreeNode.class)
                        .setSql("tree_order = tree_order + 1")
                        .eq(TreeNode::getParentId, currentNode.getParentId())
                        .eq(TreeNode::getTreeId, currentNode.getTreeId())
                        .ge(TreeNode::getTreeOrder, currentNode.getTreeOrder())
                );
                treeNodeMapper.insert(newNode);
            }
            case OperationTypeEnum.SIBLING_DOWN -> {
                // 向下创建同级节点，后面的同级节点顺序后移
                newNode.setParentId(currentNode.getParentId());
                newNode.setTreeOrder((short) (currentNode.getTreeOrder() + 1));
                this.update(Wrappers.lambdaUpdate(TreeNode.class)
                        .setSql("tree_order = tree_order + 1")
                        .eq(TreeNode::getParentId, currentNode.getParentId())
                        .eq(TreeNode::getTreeId, currentNode.getTreeId())
                        .ge(TreeNode::getTreeOrder, currentNode.getTreeOrder() + 1)
                );
                treeNodeMapper.insert(newNode);
            }

        }
        return queryTreeList();
    }

    /**
     * 复制粘贴节点（保持层级）
     */
    @Transactional
    public List<TreeNodeDto> copyNodes(CopyNodeQuery query) {
        TreeNode targetParent = treeNodeMapper.selectById(query.getSelectedId());
        if (targetParent == null) {
            return queryTreeList();
        }
        var originalIdList = query.getList().stream().map(CopyNodeQuery.CopyNode::getOriginalId).toList();
        var treeNodeList = this.listByIds(originalIdList);
        var treeNodeDtos = buildTree(treeNodeList);
        treeNodeDtos.stream()
                .sorted(Comparator.comparingInt(TreeNode::getDepth)
                        .thenComparingInt(TreeNode::getTreeOrder))
                .forEach(node -> {
                    node.setId(null);
                    if (originalIdList.contains(node.getParentId())) {
                        // 不是选中节点中的顶层节点，只需新建一个node替换
                        TreeNode entity = TreeNodeConverter.INSTANCE.toEntity(node);
                        treeNodeMapper.insert(entity);
                        node.setId(entity.getId());
                        node.getChildren().forEach(child -> child.setParentId(entity.getId()));
                        return;
                    }
                    node.setParentId(targetParent.getId());
                    TreeNode entity = TreeNodeConverter.INSTANCE.toEntity(node);
                    treeNodeMapper.insert(entity);
                    node.setId(entity.getId());
                    node.getChildren().forEach(child -> child.setParentId(entity.getId()));
                });
        return queryTreeList();
    }

    /**
     * 删除节点，删除节点需要选择连续节点，如： B、 B-a、 B-a-a
     * 删除的逻辑就是子替父
     * TODO depth 计算
     * </p>
     * node-root
     * ├── node A
     * ├── node B
     * └──node B-a
     * ├── node B-a-a
     * └── node B-a-b
     * ├──node B-b
     * └──node B-c
     */
    @Transactional(rollbackFor = Exception.class)
    public List<TreeNodeDto> deleteNodes(DeleteNodeQuery query) {
        // 待删除节点
        List<TreeNode> treeNodeList = treeNodeMapper.selectBatchIds(query.getDeleteList());
        // 父节点id
        Set<Long> parentIdSet = treeNodeList.stream().map(TreeNode::getParentId).collect(Collectors.toSet());
        // 查询待删除节点的子节点和父节点
        List<TreeNode> relatedNodeList = treeNodeMapper.selectList(Wrappers.lambdaUpdate(TreeNode.class)
                .in(TreeNode::getParentId, query.getDeleteList())
                .or()
                .in(!CollectionUtils.isEmpty(parentIdSet), TreeNode::getId, parentIdSet));
        treeNodeMapper.deleteBatchIds(query.getDeleteList());
        if (!treeNodeList.addAll(relatedNodeList)) {
            return queryTreeList();
        }
        Map<Long, TreeNode> treeNodeMap = treeNodeList.stream().collect(Collectors.toMap(TreeNode::getId, node -> node));
        // 有相关节点
        List<TreeNodeDto> treeNodeDtos = buildTree(treeNodeList);
        treeNodeDtos.forEach(node -> {
            if (query.getDeleteList().contains(node.getId())) {
                // 获取父节点
                var parentNode = treeNodeMap.get(node.getParentId());

                // 获取子节点
                if (!CollectionUtils.isEmpty(node.getChildren())) {
                    // 讲子节点提升到父节点下 TODO 重排序
                    node.getChildren().forEach(childNode -> treeNodeMap.get(childNode.getId()).setParentId(parentNode.getId()));
                }
            }
        });
        // 更新
        this.updateBatchById(treeNodeList);
        return queryTreeList();
    }

}
